
#include "stdafx.h"
#include "CGame.h"

extern "C" int GetDeviceModel();

#ifdef MAC_OS
//extern "C" int GetPhoneOrientation();
//extern "C" const char* GetRealFilePath(const char* filename);
#include <assert.h>
#include <pthread.h>
#endif

CGame* CGame::_this = NULL;
//CMapDesign** CGame::_designs=NULL;
UINT32	CGame::_touch_id_gen = 0;

CGame::CGame(CDevice device)
{
	_this = this;
	_last_frame_time = 0;
	_run_time = 0;
	_d = device;

}

CGame::~CGame()
{

}

void CGame::Init()
{
	//CMath::PRE_RANDOM();
	
	_isExit = false;
	_isPause = false;
	_output_buffer = NULL;
	_frame_counter = 0;
	
	//_texts = new UNICHAR**[NUM_TEXT_PACKAGES];
	//_text_lens = new UINT16*[NUM_TEXT_PACKAGES];
	//for (int i = 0; i < NUM_TEXT_PACKAGES; i++)
	//{
		//_texts[i] = NULL;
		//_text_lens[i] = NULL;
	//}

	//calculate game design scale appropiate with device screen
	_game_orientation = (GAME_DESIGN_WIDTH>GAME_DESIGN_HEIGHT)?ORIENTATION_LANDSCAPE_270:ORIENTATION_PORTRAIT;
	int display_scr_w = (_game_orientation == _d.Orientation)?_d.SCR_W:_d.SCR_H;
	int display_scr_h = (_game_orientation == _d.Orientation)?_d.SCR_H:_d.SCR_W;

	_game_scale_w = (float)display_scr_w/(float)GAME_DESIGN_WIDTH;
	_game_scale_h = (float)display_scr_h/(float)GAME_DESIGN_HEIGHT;
	printf("_gscalew:%0.2f _gscaleh:%0.2f\n",_game_scale_w,_game_scale_h);
	_game_scale = (_game_scale_w<_game_scale_h)?_game_scale_w:_game_scale_h;
	int new_game_width = G(GAME_DESIGN_WIDTH);
	int new_game_height = G(GAME_DESIGN_HEIGHT);

	if((GAME_DESIGN_ANCHOR & _LEFT) > 0){
		_game_x = 0;
	}else if((GAME_DESIGN_ANCHOR & _RIGHT) > 0){
		_game_x = display_scr_w - new_game_width;
	}else if((GAME_DESIGN_ANCHOR & _HCENTER) > 0){
		_game_x = (display_scr_w - new_game_width)/2;
	}

	if((GAME_DESIGN_ANCHOR & _TOP) > 0){
		_game_y = 0;
	}else if((GAME_DESIGN_ANCHOR & _BOTTOM) > 0){
		_game_y = display_scr_h - new_game_height;
	}else if((GAME_DESIGN_ANCHOR & _VCENTER) > 0){
		_game_y = (display_scr_h - new_game_height)/2;
	}
	_game_right = _game_x + new_game_width;
	_game_bottom = _game_y + new_game_height;
	_game_dright = display_scr_w - _game_right;
	_game_dbottom = display_scr_h - _game_bottom;
	printf("game_x:%d game_y:%d\n",_game_x,_game_y);

	//init OpenGL or graphich devices
	printf("g_orientation:%d device_orientation:%d\n",_game_orientation,_d.Orientation);
	_g = new GLESLib(_game_orientation != _d.Orientation,_game_orientation,_d.SCR_W,_d.SCR_H);
	_g->Init();
	
//#if !defined(MAC_OS)
	_g->ConfigOpenGL();
//#endif
	//calculate the screen
	_g->SetViewPort(_d.SCR_W,_d.SCR_H);
	_touches = new CTouch*[MAX_TOUCHES];
	for (int i = 0; i < MAX_TOUCHES; i++)
	{
		_touches[i] = NULL;
	}
	_num_touches = 0;
	_active_touch = 0;

	_current_num_animal = 0;

	_fps_time_limit = 1000/FPS_LIMIT;

    InitEx();
}

void CGame::Release()
{
	_sprite.Unload();
	
	SAFE_DEL(_g);
	
	for (int i = 0; i < MAX_TOUCHES; i++)
	{
		SAFE_DEL(_touches[i]);
	}
	SAFE_DEL_ARRAY(_touches);
#if defined(USE_TIMER)
#endif

	ReleaseEx();
}

void CGame::FlushGraphics()
{
	_g->Flush2D();
}

void CGame::Run()
{
	if (_isExit || _isPause)
	{
		return;
	}

	//update and render game
	UpdateAndRender();

	//process event
	ProcessSytemEvents();

	//control fps and get frame time
	UINT32 current_time = GetTime();
	_frame_dt = current_time - _last_frame_time;
	_last_frame_time = current_time;
	//printf ("current_time %d  _last_frame_time %d _frame_dt: %d \n",current_time, _last_frame_time, _frame_dt);
	
	//int sleep_time = 0;

	FlushGraphics();
	if (_frame_dt < _fps_time_limit)
	{
		int sleep_time = _fps_time_limit - _frame_dt;
		Sleep(sleep_time);
		_frame_dt += sleep_time;
	}
	
	_frame_counter++;
}

void CGame::Pause()
{
	_isPause = true;
    PauseEx();
}

void CGame::Resume()
{
	_isPause = false;
	ResumeEx();
}

void CGame::Exit()
{
	_isExit = true;
}

void CGame::SetGameState(int iNewState, bool isCleaning)
{
	if (isCleaning)
	{
		_GameStateNew = iNewState;
		_GameSubState = k_DESTROY;
		ClearTouchesEnd();
		//ClearAllTouch();
	}
	else
	{
		_GameStateOld = _GameState;
		_GameState = iNewState;
		_GameSubState = k_INIT;
		ClearTouchesEnd();
		//ClearAllTouch();
	}
	_run_time = 0;
}

void CGame::SetSubState(int iNewSubState)
{
	_GameSubState = iNewSubState;
	ClearTouchesEnd();
	//ClearAllTouch();
	_run_time = 0;
}

void CGame::FreeOutputBuffer()
{
	SAFE_DEL_ARRAY(_output_buffer);
}

//gfx resource
void CGame::LoadSprite()
{
	_sprite.Load();
}
void CGame::LoadDesigner(int  designer_id)
{
	
}

void CGame::NotifyTouchesBegan(int touch_id, int x, int y, int tap_count)
{

	if(_game_orientation != _d.Orientation){
		if(_game_orientation == ORIENTATION_LANDSCAPE_270){
			int tmp = x;
			x = y;
			y = _d.SCR_W - tmp;
		}else{
			int tmp = y;
			y = x;
			x = _d.SCR_H - tmp;
		}
	}
	//printf("touch begin id %d \n", touch_id);
	if (_num_touches >= MAX_TOUCHES)
	{
		//find oldest touch end
		int index = -1;
		unsigned int time = 0;
		for (int i = 0; i < _num_touches; i++)
		{
			if (_touches[i]->_state == TOUCH_UP)
			{
				if (index == -1 || time > _touches[i]->_touch_time)
				{
					time = _touches[i]->_touch_time;
					index = i;
				}
			}
		}
		
		//clear this touch
		if (index >= 0)
		{
			CTouch* tmp = NULL;
			tmp = _touches[index];
			_touches[index] = _touches[_num_touches-1];
			_touches[_num_touches-1] = tmp;
			_num_touches--;
		}
	}
	
	if (_num_touches < MAX_TOUCHES)
	{
		if (_touches[_num_touches] == NULL)
		{
			_touches[_num_touches] = new CTouch(touch_id, x, y, TOUCH_DOWN, tap_count, _frame_counter);
		}
		else
		{
			_touches[_num_touches]->Init(touch_id, x, y, TOUCH_DOWN, tap_count, _frame_counter);
		}
		_num_touches++;
	}
	_active_touch++;
	UpdateTouch(x, y, TOUCH_DOWN, touch_id, tap_count);
}

void CGame::NotifyTouchesMoved(int touch_id, int x, int y, int tap_count)
{
	if(_game_orientation != _d.Orientation){
		if(_game_orientation == ORIENTATION_LANDSCAPE_270){
			
			int tmp = x;
			x = y;
			y = _d.SCR_W - tmp;
		}else{
			int tmp = y;
			y = x;
			x = _d.SCR_H - tmp;
		}
	}
	for (int i = 0; i < _num_touches; i++)
	{
		if (_touches[i]->_id == touch_id)
		{
			_touches[i]->Set(x, y, TOUCH_DRAG, tap_count, _frame_counter);
		}
	}
	UpdateTouch(x, y, TOUCH_DRAG, touch_id, tap_count);
}

void CGame::NotifyTouchesEnd(int touch_id, int x, int y, int tap_count)
{
	if(_game_orientation != _d.Orientation){
		if(_game_orientation == ORIENTATION_LANDSCAPE_270){
			int tmp = x;
			x = y;
			y = _d.SCR_W - tmp;
		}else{
			int tmp = y;
			y = x;
			x = _d.SCR_H - tmp;
		}
	}
	//printf("touch end id %d\n", touch_id);
	for (int i = 0; i < _num_touches; i++)
	{
		if (_touches[i]->_id == touch_id)
		{
			_touches[i]->Set(x, y, TOUCH_UP, tap_count, _frame_counter);
		}
	}
	//note: don't clear touch end here.
	_active_touch --;
	
	UpdateTouch(x, y, TOUCH_UP, touch_id, tap_count);
}

void CGame::ClearTouchesEnd()
{
	CTouch* tmp = NULL;
	for (int i = _num_touches-1; i >= 0; i--)
	{
		if (_touches[i] == NULL ||
			_touches[i]->_state == TOUCH_UP)
		{
			tmp = _touches[i];
			_touches[i] = _touches[_num_touches-1];
			_touches[_num_touches-1] = tmp;
			
			_num_touches--;
		}
	}
	_active_touch = _num_touches;
}

void CGame::ClearAllTouch()
{
    _num_touches = 0;
	_active_touch = 0;
}

void CGame::ProcessSytemEvents()
{
	int keySrc;
	for(int i = 0; i< EVENT_MAX_RECORD; i++){
		//remove all unuse event
		if(_e._events[i]._state == EVENT_STATE_OUT_OF_DATE){
			//printf("delete event\n");
			if(_e._events[i]._data){
				
				delete[] _e._events[i]._data;
				_e._events[i]._data = NULL;
				_e._events[i]._data_len = 0;
			}
			_e._events[i]._state = EVENT_STATE_DEATH;
		}
		else if (_e._events[i]._id == ECODE_KEY_PRESS && _e._events[i]._data != NULL)
		{
			keySrc = (int)*_e._events[i]._data;
			printf("\nkeySrc = %d ", keySrc);
			switch(keySrc)
			{
				case KEY_GAME_G:
					CreateAnimal(_IMAGE_TYPE_CHICKEN);
					break;
				case KEY_GAME_V:
					CreateAnimal(_IMAGE_TYPE_DUCK);
					break;
				case KEY_GAME_N:
					CreateAnimal(_IMAGE_TYPE_GEESE);
					break;
				case KEY_NARROW_LEFT:
					_on_key_narrow_left = true;
					break;
				case KEY_NARROW_RIGHT:
					_on_key_narrow_right = true;
					break;
			}
		}
		else if (_e._events[i]._id == ECODE_KEY_RELEASE && _e._events[i]._data != NULL)
		{
			keySrc = (int)*_e._events[i]._data;
			//printf("\nkeySrc = %d ", keySrc);
			switch(keySrc)
			{
				case KEY_NARROW_LEFT:
					_on_key_narrow_left = false;
					break;
				case KEY_NARROW_RIGHT:
					_on_key_narrow_right = false;
					break;
			}
		}
		//mark unuse event to delete late
		if(_e._events[i]._state == EVENT_STATE_WAIT)_e._events[i]._state = EVENT_STATE_OUT_OF_DATE;
	}
}

CGame* CGame::GetInstace(CDevice device)
{
	if (_this == NULL)
		_this = new CGame(device);
	return _this;
}

float CGame::Math_Cos(float angle)
{
	while(angle < 0)
	{
		angle += 360;
	}
	while(angle >= 360)
	{
		angle -= 360;
	}
	return _cos_table[(int)(angle/0.1)];
}

float CGame::Math_Sin(float angle)
{
	while(angle < 0)
	{
		angle += 360;
	}
	while(angle >= 360)
	{
		angle -= 360;
	}
	return _sin_table[(int)(angle/0.1)];
}